<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1,maximum-scale=1,user-scalable=no">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <!-- <link rel="stylesheet" type="text/css" href="css/index.css">
    <script type="text/javascript" src="js/index.js"></script>
    <style type="text/css"></style> -->
    <title>Document</title>
    <style>
        div{
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
        }
        .box2{
            top: 110px;
        }
    </style>
</head>

<body>
    <div class="box1"></div>
    <div class="box2"></div>
    <script>
        /**
         * @param element 待添加运动动画效果的DOM元素
         * @param attr 运动属性，如：'top', 'left', 'width', 'height'
         * @param end 运动的目标终点值
         * @param duration 限定运动的总时长
         */
        function animate(element,attr,end,duration){
            //首先停止运动动画效果的定时器
            clearInterval(element.timer)//element.timer表示将定时器绑定到元素身上，当有多个定时器的时候，不同的元素就有自己专属的定时器不会导致冲突
            //通过获取元素的外部样式属性来获取元素的初始状态
            const start=parseFloat(window.getComputedStyle(element,null)[attr])
            //元素的变化的动画速度
            const speed=(end-start)/duration
            //拿到定时器启动前的时间
            const startTime=Date.now()
            //运动一次的方法
            function move(){
                 //获取元素已经运动了多少时间
                 const elapsed=Math.min(duration,Date.now()-startTime)//因为定时器是每1000/60毫秒执行一次，所以定时器结束时Date.now()可能会大于总时长，所以这里取较小的那一个值
                //拿到元素最终的位置
                const result=elapsed*speed+start
                //设置元素的样式
                element.style[attr]=result+'px'
                //判断定时器启动的条件
                if(elapsed!==duration){
                    //因为setTimeout方法只能执行一次所以使用递归调用move()实现重复启动定时器达到运动的效果
                    element.timer=setTimeout(move,1000/60)//1000/60表示1秒60帧的画面
                }
            }
            //执行move(),实现运动效果
            move()
        }
        document.querySelector('.box1').addEventListener('mouseenter',function(e){
            animate(e.target,'width',500,1000)
        },false)
        document.querySelector('.box1').addEventListener('mouseleave',function(e){
            animate(e.target,'width',100,1000)
        },false)
        document.querySelector('.box2').addEventListener('mouseenter',function(e){
            animate(e.target,'width',400,1000)
        },false)
        document.querySelector('.box2').addEventListener('mouseleave',function(e){
            animate(e.target,'width',100,1000)
        },false)
    </script>
</body>

</html>